Repository navigation
Conversation
aff9260 to
8b5f49b
Compare
mglaman
left a comment
There was a problem hiding this comment.
Thanks for this, and for the validation run against contrib. 121 true positives and no false positives is a strong result for a new rule. I checked the behavior against core: on 11.4 a non-attribute 5th argument triggers the deprecation, on main it throws InvalidArgumentException, and an omitted or null argument does neither, so skipping that case is right. The tests pass merged onto current main.
Let's keep it opt-in. Since you run the project update bot, turning it on there gets the coverage this is for.
One fix and a few smaller things:
- The inline comment below: the default rule can pick up the wrong constructor.
- nit: make the two concrete rules
final. - nit: add
pluginManagerAttributeDiscoveryRuleto the README'sdrupal.rulesdocs so people can find it. - Not blocking: for the forwarded-parameter case,
ParameterReflection::getDefaultValue()at the call site might replace some of the manual AST walking. Fine to leave as is given the results.
|
|
||
| $classNode = $node->getOriginalNode(); | ||
| $finder = new NodeFinder(); | ||
| $constructor = $finder->findFirst( |
There was a problem hiding this comment.
findFirst() descends into method bodies, so an anonymous class with its own __construct in a method above the real constructor gets picked instead. ClassLike::getMethod() only looks at the class's own methods:
$constructor = $classNode->getMethod('__construct');
if ($constructor === null) {
return [];
}|
Reviewed the comments, confirmed and fixed :) |
|
Here is my LLM agents's review as it was about to write a regex custom checker for this and I thought it should review this PR instead :D It affects 9 projects with 15 instances of the error in Drupal CMS, so this will be likely useful for contrib. I tried this on the projects from our Drupal 12 readiness work for Drupal CMS. It works well, and I would like to use it in Upgrade Status. Setup: this PR at 39013bf, PHPStan 2.3.5, Drupal 11.5.x-dev, level 0, with Result: we had fixed 9 of these projects by hand for this problem: crop, ctools, field_group, field_validation, google_tag, key, scheduler, symfony_mailer_lite and webform. The rule found all 9 and no other project, with 15 errors in total. There were no false positives. Some of these are hard to find without type inference. A regex prototype of mine only found 7 of the 9.
All 15 errors came from Edge cases. I also ran a small test module with these managers:
I don't think any of these should block this PR:
Upgrade Status integration. I tried this on a local branch, and it needed three small changes:
With those changes, a test module with one annotation manager and one attribute manager reports only the annotation manager. This passes on Drupal 11.5 and on 12.0. Opt-in works fine for us. Once this is in a release, Upgrade Status can turn the rule on, and its users will get this check for Drupal 12. |
Hi! AI was used to make this, i've tried to verify against contrib best i could to make sure we don't screw ourselves over. The results were quite promising. This should help up to 500 projects in contrib with deprecation status and project analysis.
Triggered by https://drupal.slack.com/archives/C08QW79LJ94/p1793842732050899 which was already mentioned to me by berdir in https://drupal.slack.com/archives/C08QW79LJ94/p1787647148732209.
Introduction
Core now throws on plugin managers that only support annotation discovery (#3577900, CR 3522776). Nothing in the PHPStan or Upgrade Status toolchain sees it: the check in
DefaultPluginManager::__construct()is a runtime@trigger_error, not a@deprecatedtag. The result is bot runs that call a module "Drupal 12 compatible" when its managers will fatal. json_ld_schema is one example.This PR adds the missing static check.
What it does
It reports a
DefaultPluginManagersubclass whoseparent::__construct()receives a non-attribute class as the 5th argument ($plugin_definition_attribute_name). The 5th argument can be positional or the named argument.There are two rules behind a single toggle:
PluginManagerAttributeDiscoveryRulehandles a literal::class, a string literal, or a local variable that holds one. Identifier:pluginManager.attributeDiscoveryMissing.PluginManagerAttributeDiscoveryDefaultRulehandles astatic::$prop/self::$propdefault, or a forwarded constructor parameter default. Identifier:pluginManager.attributeDiscoveryMissingDefault. Its message says the default may be overridden by a subclass or caller, because that can't be seen statically.Both are off by default. Enable them with:
Both rules do nothing when
AttributeInterfacecan't be resolved (Drupal older than 10.2). A manager that omits the 5th argument is not reported, matching core. The fix is to pass an Attribute class as the 5th argument and keep the Annotation class as the 6th. That works from 10.2.0.Why opt-in
Most existing rules are now on by default, so I'd normally follow that. I kept this one off because it can't be fixed on a module that still supports 10.0 or 10.1, and I'd rather you make that call. Given the numbers below I'm happy to flip the default if you want it on.
Validation
I ran it against the 100 highest-install contrib projects that a code-index query flagged as having annotation-only managers (dev branches, Drupal 11 core).
parent::__construct()) and graphql (annotation class supplied only inservices.yml).Known limitations
services.yml(class: DefaultPluginManagerwith all arguments in YAML) aren't detected, and neither isnew DefaultPluginManager(...).ServiceMapdropsarguments:, so covering this needs a change there. I'd do that separately.Tests
The new rule tests pass (4 of 4). The full suite has one failure:
InspectorTypeExtensionTestbug-857. It also fails on a cleanmainand is not touched by this branch.